#ifndef S3C2440_H
#define S3C2440_H

#define S3C24X0_UART_CHANNELS		3
#define S3C24X0_SPI_CHANNELS		2

/* S3C2440 only supports 512 Byte HW ECC */
#define S3C2440_ECCSIZE			512
#define S3C2440_ECCBYTES		3

/* S3C2440 device base addresses */
#define S3C24X0_MEMCTL_BASE		0x48000000
#define S3C24X0_USB_HOST_BASE		0x49000000
#define S3C24X0_INTERRUPT_BASE		0x4A000000
#define S3C24X0_DMA_BASE		0x4B000000
#define S3C24X0_CLOCK_POWER_BASE	0x4C000000
#define S3C24X0_LCD_BASE		0x4D000000
#define S3C24X0_NAND_BASE		0x4E000000
#define S3C24X0_UART_BASE		0x50000000
#define S3C24X0_TIMER_BASE		0x51000000
#define S3C24X0_USB_DEVICE_BASE		0x52000140
#define S3C24X0_WATCHDOG_BASE		0x53000000
#define S3C24X0_I2C_BASE		0x54000000
#define S3C24X0_I2S_BASE		0x55000000
#define S3C24X0_GPIO_BASE		0x56000000
#define S3C24X0_RTC_BASE		0x57000040
#define S3C24X0_ADC_BASE		0x58000000
#define S3C24X0_SPI_BASE		0x59000000
#define S3C24X0_SDI_BASE		0x5A000000
#define S3C24X0_AC97_BASE		0x5B000000

#define oNFCONF				0x00
#define oNFCONT				0x04

/* S3C2440 interrupts */
enum s3c24x0_interrupt {
	S3C24X0_INTERRUPT_EINT0		= (0x1),
	S3C24X0_INTERRUPT_EINT1		= (0x1<<1),
	S3C24X0_INTERRUPT_EINT2		= (0x1<<2),
	S3C24X0_INTERRUPT_EINT3		= (0x1<<3),
	S3C24X0_INTERRUPT_EINT4_7	= (0x1<<4),
	S3C24X0_INTERRUPT_EINT8_23	= (0x1<<5),
	S3C24X0_INTERRUPT_CAM		= (0x1<<6),
	S3C24X0_INTERRUPT_BATT_FLT	= (0x1<<7),
	S3C24X0_INTERRUPT_TICK		= (0x1<<8),
	S3C24X0_INTERRUPT_WDT		= (0x1<<9),
	S3C24X0_INTERRUPT_TIMER0	= (0x1<<10),
	S3C24X0_INTERRUPT_TIMER1	= (0x1<<11),
	S3C24X0_INTERRUPT_TIMER2	= (0x1<<12),
	S3C24X0_INTERRUPT_TIMER3	= (0x1<<13),
	S3C24X0_INTERRUPT_TIMER4	= (0x1<<14),
	S3C24X0_INTERRUPT_UART2		= (0x1<<15),
	S3C24X0_INTERRUPT_LCD		= (0x1<<16),
	S3C24X0_INTERRUPT_DMA0		= (0x1<<17),
	S3C24X0_INTERRUPT_DMA1		= (0x1<<18),
	S3C24X0_INTERRUPT_DMA2		= (0x1<<19),
	S3C24X0_INTERRUPT_DMA3		= (0x1<<20),
	S3C24X0_INTERRUPT_SDI		= (0x1<<21),
	S3C24X0_INTERRUPT_SPI0		= (0x1<<22),
	S3C24X0_INTERRUPT_UART1		= (0x1<<23),
	S3C24X0_INTERRUPT_NFCON		= (0x1<<24),
	S3C24X0_INTERRUPT_USBD		= (0x1<<25),
	S3C24X0_INTERRUPT_USBH		= (0x1<<26),
	S3C24X0_INTERRUPT_IIC		= (0x1<<27),
	S3C24X0_INTERRUPT_UART0		= (0x1<<28),
	S3C24X0_INTERRUPT_SPI1		= (0x1<<29),
	S3C24X0_INTERRUPT_RTC		= (0x1<<30),
	S3C24X0_INTERRUPT_ADC		= (0x1<<31),
	S3C24X0_INTERRUPT_ALLMASK	= (0xFFFFFFFF),
};

/* S3C2440 sub interrupts */
enum s3c24x0_sub_interrupt {
	S3C24X0_SUB_INTERRUPT_RXD0	= (0x1),
	S3C24X0_SUB_INTERRUPT_TXD0	= (0x1<<1),
	S3C24X0_SUB_INTERRUPT_ERR0	= (0x1<<2),
	S3C24X0_SUB_INTERRUPT_RXD1	= (0x1<<3),
	S3C24X0_SUB_INTERRUPT_TXD1	= (0x1<<4),
	S3C24X0_SUB_INTERRUPT_ERR1	= (0x1<<5),
	S3C24X0_SUB_INTERRUPT_RXD2	= (0x1<<6),
	S3C24X0_SUB_INTERRUPT_TXD2	= (0x1<<7),
	S3C24X0_SUB_INTERRUPT_ERR2	= (0x1<<8),
	S3C24X0_SUB_INTERRUPT_TC	= (0x1<<9),
	S3C24X0_SUB_INTERRUPT_ADC_S	= (0x1<<10),
	S3C24X0_SUB_INTERRUPT_CAM_C	= (0x1<<11),
	S3C24X0_SUB_INTERRUPT_CAM_P	= (0x1<<12),
	S3C24X0_SUB_INTERRUPT_WDT	= (0x1<<13),
	S3C24X0_SUB_INTERRUPT_AC97	= (0x1<<14),
	S3C24X0_SUB_INTERRUPT_ALLMASK	= (0xFFFFFFFF),
};

/* S3C2440 external interrupts */
enum s3c24x0_ext_interrupt {
	S3C24X0_EXT_INTERRUPT_EINT4	= (0x1<<4),
	S3C24X0_EXT_INTERRUPT_EINT5	= (0x1<<5),
	S3C24X0_EXT_INTERRUPT_EINT6	= (0x1<<6),
	S3C24X0_EXT_INTERRUPT_EINT7	= (0x1<<7),
	S3C24X0_EXT_INTERRUPT_EINT8	= (0x1<<8),
	S3C24X0_EXT_INTERRUPT_EINT9	= (0x1<<9),
	S3C24X0_EXT_INTERRUPT_EINT10	= (0x1<<10),
	S3C24X0_EXT_INTERRUPT_EINT11	= (0x1<<11),
	S3C24X0_EXT_INTERRUPT_EINT12	= (0x1<<12),
	S3C24X0_EXT_INTERRUPT_EINT13	= (0x1<<13),
	S3C24X0_EXT_INTERRUPT_EINT14	= (0x1<<14),
	S3C24X0_EXT_INTERRUPT_EINT15	= (0x1<<15),
	S3C24X0_EXT_INTERRUPT_EINT16	= (0x1<<16),
	S3C24X0_EXT_INTERRUPT_EINT17	= (0x1<<17),
	S3C24X0_EXT_INTERRUPT_EINT18	= (0x1<<18),
	S3C24X0_EXT_INTERRUPT_EINT19	= (0x1<<19),
	S3C24X0_EXT_INTERRUPT_EINT20	= (0x1<<20),
	S3C24X0_EXT_INTERRUPT_EINT21	= (0x1<<21),
	S3C24X0_EXT_INTERRUPT_EINT22	= (0x1<<22),
	S3C24X0_EXT_INTERRUPT_EINT23	= (0x1<<23),
	S3C24X0_EXT_INTERRUPT_ALLMASK	= (0xFFFFFFFF),
};

/* include common stuff */
#include "s3c24x0.h"

typedef enum {
	S3C24X0_UART0,
	S3C24X0_UART1,
	S3C24X0_UART2
} S3C24X0_UARTS_NR;

static inline S3C24X0_MEMCTL * S3C24X0_GetBase_MEMCTL(void)
{
	return (S3C24X0_MEMCTL * const)S3C24X0_MEMCTL_BASE;
}

static inline S3C24X0_USB_HOST * S3C24X0_GetBase_USB_HOST(void)
{
	return (S3C24X0_USB_HOST * const)S3C24X0_USB_HOST_BASE;
}

static inline S3C24X0_INTERRUPT * S3C24X0_GetBase_INTERRUPT(void)
{
	return (S3C24X0_INTERRUPT * const)S3C24X0_INTERRUPT_BASE;
}

static inline S3C24X0_DMAS * S3C24X0_GetBase_DMAS(void)
{
	return (S3C24X0_DMAS * const)S3C24X0_DMA_BASE;
}

static inline S3C24X0_CLOCK_POWER * S3C24X0_GetBase_CLOCK_POWER(void)
{
	return (S3C24X0_CLOCK_POWER * const)S3C24X0_CLOCK_POWER_BASE;
}

static inline S3C24X0_LCD * S3C24X0_GetBase_LCD(void)
{
	return (S3C24X0_LCD * const)S3C24X0_LCD_BASE;
}

static inline S3C24X0_NAND * S3C24X0_GetBase_NAND(void)
{
	return (S3C24X0_NAND * const)S3C24X0_NAND_BASE;
}

static inline S3C24X0_UART * S3C24X0_GetBase_UART(S3C24X0_UARTS_NR nr)
{
	return (S3C24X0_UART * const)(S3C24X0_UART_BASE + (nr * 0x4000));
}

static inline S3C24X0_TIMERS * S3C24X0_GetBase_TIMERS(void)
{
	return (S3C24X0_TIMERS * const)S3C24X0_TIMER_BASE;
}

static inline S3C24X0_USB_DEVICE * S3C24X0_GetBase_USB_DEVICE(void)
{
	return (S3C24X0_USB_DEVICE * const)S3C24X0_USB_DEVICE_BASE;
}

static inline S3C24X0_WATCHDOG * S3C24X0_GetBase_WATCHDOG(void)
{
	return (S3C24X0_WATCHDOG * const)S3C24X0_WATCHDOG_BASE;
}

static inline S3C24X0_I2C * S3C24X0_GetBase_I2C(void)
{
	return (S3C24X0_I2C * const)S3C24X0_I2C_BASE;
}

static inline S3C24X0_I2S * S3C24X0_GetBase_I2S(void)
{
	return (S3C24X0_I2S * const)S3C24X0_I2S_BASE;
}

static inline S3C24X0_GPIO * S3C24X0_GetBase_GPIO(void)
{
	return (S3C24X0_GPIO * const)S3C24X0_GPIO_BASE;
}

static inline S3C24X0_RTC * S3C24X0_GetBase_RTC(void)
{
	return (S3C24X0_RTC * const)S3C24X0_RTC_BASE;
}

static inline S3C24X0_ADC * S3C24X0_GetBase_ADC(void)
{
	return (S3C24X0_ADC * const)S3C24X0_ADC_BASE;
}

static inline S3C24X0_SPI * S3C24X0_GetBase_SPI(void)
{
	return (S3C24X0_SPI * const)S3C24X0_SPI_BASE;
}

static inline S3C24X0_SDI * S3C24X0_GetBase_SDI(void)
{
	return (S3C24X0_SDI * const)S3C24X0_SDI_BASE;
}

/* PENDING BIT */
#define BIT_EINT0			(0x1)
#define BIT_EINT1			(0x1<<1)
#define BIT_EINT2			(0x1<<2)
#define BIT_EINT3			(0x1<<3)
#define BIT_EINT4_7			(0x1<<4)
#define BIT_EINT8_23			(0x1<<5)
#define BIT_BAT_FLT			(0x1<<7)
#define BIT_TICK			(0x1<<8)
#define BIT_WDT				(0x1<<9)
#define BIT_TIMER0			(0x1<<10)
#define BIT_TIMER1			(0x1<<11)
#define BIT_TIMER2			(0x1<<12)
#define BIT_TIMER3			(0x1<<13)
#define BIT_TIMER4			(0x1<<14)
#define BIT_UART2			(0x1<<15)
#define BIT_LCD				(0x1<<16)
#define BIT_DMA0			(0x1<<17)
#define BIT_DMA1			(0x1<<18)
#define BIT_DMA2			(0x1<<19)
#define BIT_DMA3			(0x1<<20)
#define BIT_SDI				(0x1<<21)
#define BIT_SPI0			(0x1<<22)
#define BIT_UART1			(0x1<<23)
#define BIT_USBD			(0x1<<25)
#define BIT_USBH			(0x1<<26)
#define BIT_IIC				(0x1<<27)
#define BIT_UART0			(0x1<<28)
#define BIT_SPI1			(0x1<<29)
#define BIT_RTC				(0x1<<30)
#define BIT_ADC				(0x1<<31)
#define BIT_ALLMSK			(0xFFFFFFFF)

#define ClearPending(bit) {	\
	rSRCPND = bit;		\
	rINTPND = bit;		\
	rINTPND;		\
}
/* Wait until rINTPND is changed for the case that the ISR is very short. */

#define __REG(x)			(*(volatile unsigned long *)(x))
#define __REGl(x)			(*(volatile unsigned long *)(x))
#define __REGw(x)			(*(volatile unsigned short *)(x))
#define __REGb(x)			(*(volatile unsigned char *)(x))
#define __REG2(x,y)			(*(volatile unsigned long *)((x) + (y)))

/* Nand flash controller */
#define NFDATA8				(*(volatile unsigned char *)0x4E000010)
#define NFDATA16			(*(volatile unsigned short *)0x4E000010)
#define NFDATA32			(*(volatile unsigned *)0x4E000010)

#define NFCONF				__REG(0x4E000000)
#define NFCONT				__REG(0x4E000004)
#define NFCMD				__REG(0x4E000008)
#define NFADDR				__REGb(0x4E00000C)
#define NFMECCD0			__REG(0x4E000014)
#define NFMECCD1			__REG(0x4E000018)
#define NFSECCD				__REG(0x4E00001C)
#define NFSTAT				__REG(0x4E000020)
#define NFESTAT0			__REG(0x4E000024)
#define NFESTAT1			__REG(0x4E000028)
#define NFMECC0				__REG(0x4E00002C)
#define NFMECC1				__REG(0x4E000030)
#define NFSECC				__REG(0x4E000034)
#define NFSBLK				__REG(0x4E000038)

#define S3C2410_MISCCR_USBDEV		(0<<3)
#define S3C2410_MISCCR_USBHOST		(1<<3)

#define S3C2410_MISCCR_CLK0_MPLL	(0<<4)
#define S3C2410_MISCCR_CLK0_UPLL	(1<<4)
#define S3C2410_MISCCR_CLK0_FCLK	(2<<4)
#define S3C2410_MISCCR_CLK0_HCLK	(3<<4)
#define S3C2410_MISCCR_CLK0_PCLK	(4<<4)
#define S3C2410_MISCCR_CLK0_DCLK0	(5<<4)
#define S3C2410_MISCCR_CLK0_MASK	(7<<4)

#define S3C2410_MISCCR_CLK1_MPLL	(0<<8)
#define S3C2410_MISCCR_CLK1_UPLL	(1<<8)
#define S3C2410_MISCCR_CLK1_FCLK	(2<<8)
#define S3C2410_MISCCR_CLK1_HCLK	(3<<8)
#define S3C2410_MISCCR_CLK1_PCLK	(4<<8)
#define S3C2410_MISCCR_CLK1_DCLK1	(5<<8)
#define S3C2410_MISCCR_CLK1_MASK	(7<<8)

#define S3C2410_MISCCR_USBSUSPND0	(1<<12)
#define S3C2410_MISCCR_USBSUSPND1	(1<<13)

#define S3C2410_MISCCR_nRSTCON		(1<<16)

#define S3C2410_MISCCR_nEN_SCLK0	(1<<17)
#define S3C2410_MISCCR_nEN_SCLK1	(1<<18)
#define S3C2410_MISCCR_nEN_SCLKE	(1<<19)
#define S3C2410_MISCCR_SDSLEEP		(7<<17)

#define S3C2410_CLKSLOW_UCLK_OFF	(1<<7)
#define S3C2410_CLKSLOW_MPLL_OFF	(1<<5)
#define S3C2410_CLKSLOW_SLOW		(1<<4)
#define S3C2410_CLKSLOW_SLOWVAL(x)	(x)
#define S3C2410_CLKSLOW_GET_SLOWVAL(x)	((x) & 7)

#endif

